package com.dq.demos.web.utils;

import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.http.entity.ContentType;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.mychain.gov.sdk.base.BaseRestResult;
import com.alipay.mychain.gov.sdk.base.DecryptAndVerifyUtils;
import com.alipay.mychain.gov.sdk.base.FileResultZww;
import com.alipay.mychain.gov.sdk.base.GenericResult;
import com.alipay.mychain.gov.sdk.base.HttpClientUtils;
import com.alipay.mychain.gov.sdk.request.SignedRequest;
import com.nuonuo.plate.extracte.BaseExtracte;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 发票上传处理
 */
public class InvoiceOfdUtil {
    private static Logger logger = LoggerFactory.getLogger(InvoiceOfdUtil.class);

    //填税号，nsrsbh，查询公司的税号
    private static String instCode          = "123305214712205444";
    //填私钥秘钥，password，税局密码
    private static String password          = "4V5lMMRSfUAaLQOJ";
    //填秘钥，pkcs8PrivateKey，税局密钥（证书）
    private static String privateKeyContent = "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
            "MIH6MFUGCSqGSIb3DQEFDTBIMCcGCSqGSIb3DQEFDDAaBBRATRjktJmGyZPEgLCK\n" +
            "YOjvHK5LmAICCAAwHQYJYIZIAWUDBAEqBBCMtCCv/5jCKiQ/E8ocH4QYBIGgH5bi\n" +
            "wqrkC5j8cK6bC2+w3zU7CllUHHAs6mkZ5dYW8viNFFfmHUc+ZTme1LpkWyhpQ1ui\n" +
            "qDQjjYgeI2lyXkBHnEjpg2cibanlBHpLnBafw8aJsBb40sZUelwOKcA7vLbdx662\n" +
            "aWchAsIAvH0/jdO68k6aF45xZhYIw4Gx+sdiWx7qNfrGfQN/huY9lL4gdsbVEmHy\n" +
            "OkbKILv7irb8IXY8tg==\n" +
            "-----END ENCRYPTED PRIVATE KEY-----";

    /**
     * 请求处理发票下载 ofd
     * @param getdate
     * @return
     * @throws Exception
     */
    public  JSONArray post_zlbp_ofd(String getdate) throws Exception{
        // 获取总页数
        // 注意：每次获取总页数接口 requestId 都需要变换，  并且获取总页数和分页数据的requestId必须保持一致
        String requestId = "FFFFFFFFFFFFFF"+"_"+ System.currentTimeMillis();
        GenericResult count = packageCount(requestId, getdate, 2);
        if(count == null) return null;
        int pagecount = JSONObject.parseObject(count.getData()).getIntValue("totalPage");
        logger.info("---->当前日期:【"+getdate+"】, 浙里办发票一共存在【"+pagecount+"】 条" );
        // OFD文件解析 // 获取分页数据和存放路径
        String bankpath = "C:\\yonyou";
//        String bankpath = SysInitQuery.getParaString("GLOBLE00000000000000", "bankpath");
        String fileDirPathSrc = bankpath + "\\" + getdate + "\\ofdjiemi1201";   // 根据自身实际路径自行修改
        String temppath = bankpath + "\\" + getdate;   // 根据自身实际路径自行修改
        checkFile(fileDirPathSrc, temppath);
        for (int i = 1; i <= pagecount; i++) {
            // 获取分页数据,并解密。  注意：获取分页数据的requestId都需要与获取总页数接口的requestId保持一致。
            GenericResult result = packageInfo(requestId, i+"");
            GenericResult decryptList= decryptList(result.getData(), temppath);
            logger.info("-----> " + result.getData());
        }
        // 获取刚刚下载好的文件地址解析成json数据
        GenericResult jsonList = getOfdToJson(fileDirPathSrc, temppath);
        logger.info("--->日期:【"+getdate+"】，下载 执行成功");
        return null;
    }

    public void checkFile(String fileDirPathSrc, String temppath) {
        File file = new File(fileDirPathSrc);
        if (file.exists()) {
            System.out.println("File exists");
        } else {
            System.out.println("File not exists, create it ...");
            //getParentFile() 获取上级目录(包含文件名时无法直接创建目录的)
            if (!file.getParentFile().exists()) {
                System.out.println("not exists");
                //创建上级目录
                file.getParentFile().mkdirs();
            }
            //在上级目录里创建文件
            file.mkdirs();
        }
        File file1 = new File(temppath);
        if (file1.exists()) {
            System.out.println("File exists");
            File[] files = file1.listFiles();
            for (File in: files) {
                in.delete();
            }
            file1.delete();
            file1.mkdirs();
        } else {
            System.out.println("File not exists, create it ...");
            //getParentFile() 获取上级目录(包含文件名时无法直接创建目录的)
            if (!file1.getParentFile().exists()) {
                System.out.println("not exists");
                //创建上级目录
                file1.getParentFile().mkdirs();
            }
            //在上级目录里创建文件
            file1.mkdirs();
        }
    }

    /**
     * 获取总页数
     * @param jgrq 加工日期
     * @param requestId
     * @param gxfbs 购销方标识
     * @throws Exception
     */
    public static GenericResult packageCount(String requestId,String jgrq, int gxfbs) throws Exception {
        JSONObject json = new JSONObject();
        json.put("authorizedNsrsbh", instCode);
        json.put("gxfbs", gxfbs);
        json.put("jgrq", jgrq);
        json.put("nsrsbh", instCode);
        json.put("requestId", requestId);
        String sign = sign(json.toJSONString());
        JSONObject requestParam = new JSONObject();
        requestParam.put("zlbUrl", "http://zlbp.zhejiang.chinatax.gov.cn/api/zww/invoice/file/getInvoiceFilePackageCount");
        requestParam.put("requestParam", sign);
        String tbjipprot = "127.0.0.1:7070";
//        String tbjipprot = "129.1.2.251:7070";
//        String tbjipprot = SysInitQuery.getParaString("GLOBLE00000000000000", "tbjipprot");
        return   RemoteCallPost("http://"+tbjipprot+"/zlb/downInvoice", requestParam.toString());// 远程调用
    }

    /**
     * 获取分页内容
     * @param pageNumber 分页数
     * @param requestId
     * @throws Exception
     */
    public static GenericResult packageInfo(String requestId,String pageNumber) throws Exception {
        JSONObject json = new JSONObject();
        json.put("nsrsbh", instCode);
        json.put("requestId", requestId);
        json.put("pageNumber", pageNumber);
        String sign = sign(json.toJSONString());
//		return post(sign, "http://zlbp.zhejiang.chinatax.gov.cn/api/zww/invoice/file/getInvoiceFilePackagesInfo");
        JSONObject requestParam = new JSONObject();
        requestParam.put("zlbUrl", "http://zlbp.zhejiang.chinatax.gov.cn/api/zww/invoice/file/getInvoiceFilePackagesInfo");
        requestParam.put("requestParam", sign);
        String tbjipprot = "127.0.0.1:7070";
//        String tbjipprot = "129.1.2.251:7070";
//        String tbjipprot = SysInitQuery.getParaString("GLOBLE00000000000000", "tbjipprot");
        return   RemoteCallPost("http://"+tbjipprot+"/zlb/downInvoice", requestParam.toString());// 远程调用
    }

    /**
     * 获取签名认证
     * @param jsonStr
     * @return
     * @throws Exception
     */
    private static String sign(String jsonStr) throws Exception{
        JSONObject requestParam = new JSONObject();
        String string =  null;
        try{
//            String tbjipprot = "129.1.2.251:7070";
            String tbjipprot = "127.0.0.1:7070";
//            String tbjipprot = SysInitQuery.getParaString("GLOBLE00000000000000", "tbjipprot");
            requestParam.put("jsonStr", jsonStr);
            requestParam.put("instCode", instCode);
            requestParam.put("privateKeyContent", privateKeyContent);
            requestParam.put("password", password);
            string = HttpUtils.sendPost("http://"+tbjipprot+"/zlb/getSign", requestParam.toString());
            logger.info("-----> 浙里办签名响应【"+string+"】");
        }catch(Exception  e){
            throw new Exception("#######浙里办签名处理失败:"+e.getMessage());
        }
        return string;
    }

    private static GenericResult post(String jsonStr, String uri) throws Exception {
        String response = null;
        try {
            response = HttpClientUtils.doPost(uri, jsonStr, ContentType.APPLICATION_JSON);
        } catch (Exception e) {
            throw new Exception("请求下载返回异常" + e.getMessage());
        }

        BaseRestResult baseRestResult = JSON.parseObject(response, BaseRestResult.class);
        GenericResult result = JSON.parseObject(response, GenericResult.class);
        return result;
    }

    private static GenericResult RemoteCallPost(String jsonStr, String json) throws Exception {
        String response = null;
        try {
            response = HttpUtils.sendPost(jsonStr, json.toString());;
        } catch (Exception e) {
            throw new Exception("请求下载返回异常" + e.getMessage());
        }
        GenericResult result = JSON.parseObject(response, GenericResult.class);
        logger.info("----> 请求下载发票返回信息【"+result+"】");
        return result;
    }

    /**
     * 解析ofd文件下载到本地文件夹
     * @param dataList
     * @param fileDirPathSrc
     * @return
     * @throws IOException
     */
    public GenericResult decryptList(String dataList,String fileDirPathSrc) throws IOException {
        List<FileResultZww> fileResultZwwList = JSON.parseArray(dataList, FileResultZww.class);
        GenericResult r= new GenericResult();
        List<String> filesPath=new ArrayList<>();
        AtomicInteger total= new AtomicInteger(1);
        for(FileResultZww frz : fileResultZwwList){
            try {
                DecryptAndVerifyUtils decryptAndVerifyUtils = new DecryptAndVerifyUtils(instCode, password, privateKeyContent);
                byte[] data = decryptAndVerifyUtils.decryptZww(frz);
                String filePath = fileDirPathSrc + "\\" + frz.getFileName();  //
                DataOutputStream out = new DataOutputStream(new FileOutputStream(filePath));
                byte[] b = data;
                for (int i = 0; i < b.length; i++) {
                    out.writeByte(b[i]);
                }
                out.flush();
                out.close();
                filesPath.add(filePath);
                total.getAndIncrement();
            } catch (Exception e) {
                logger.error("----->ofd文件下载异常:"+e.getMessage());
            }
        }
        r.setSuccess(true); r.setData(JSONObject.toJSONString(filesPath));r.setErrorCode("200");
        r.setErrorMsg("解密下载完成!共解密:"+fileResultZwwList.size()+"份,成功:"+filesPath.size()+"份.");
        return r;
    }


    /**
     * 解析ofd文件转为json格式数据
     * @param fileDirPathSrc
     * @param temppath
     * @return
     * @throws Exception
     */
    public GenericResult getOfdToJson(String fileDirPathSrc, String temppath) throws Exception{
        GenericResult r=new GenericResult();
        InputStream ins = null;
        OutputStream os = null;
        InputStream is = null;
        try {
            List<JSONObject> jsonList=new ArrayList<>();
            File file = new File(temppath);
            File[] files = file.listFiles();
            File[] var4 = files;
            int var5 = files.length;
            for(int var6 = 0; var6 < var5; ++var6) {
                File f = var4[var6];
                if (!f.getName().endsWith(".xml")) {
                    is = new FileInputStream(f);
                    BaseExtracte baseExtracte = new BaseExtracte();
                    JSONObject jsonObject = baseExtracte.readXbrl(is);
                    System.out.println("---->发票文件JSON: 【"+jsonObject+"】");
                    jsonList.add(jsonObject);
                    // 解析json转化为xml保存起来
                    downXML(jsonObject, fileDirPathSrc);
                    String filepath = fileDirPathSrc + "\\" + jsonObject.getString("NumberOfInvoice")+".ofd";
                    File newfile = new File(filepath);
                    File fileodf = new File(fileDirPathSrc);
                    ins = new FileInputStream(f);
                    if(!fileodf.exists()) {
                        fileodf.mkdirs();
                        fileodf.setReadable(true);
                        fileodf.setWritable(true);
                        fileodf.setExecutable(true);
                    }
                    os = new FileOutputStream(newfile);
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = ins.read(buffer)) > 0) {
                        os.write(buffer, 0, length);
                    }
                    os.flush();
                }
            }
            return null;
        }
        catch (IOException e) {
            throw new Exception(e);
        }finally {
            if(ins != null) {ins.close();}
            if(is != null) {is.close();}
            if(os != null) {os.close();}
        }
    }

    /**
     * 将json转化为xml文件并下载
     * @param json
     * @param fileDirPathSrc
     * @throws Exception
     */
    private void downXML(JSONObject json,String fileDirPathSrc) throws Exception{
        InputStream ins = null;
        OutputStream baos = null;
        try {
            String xmldate = FormatDataUtils.hanlerXML(json);
            String xbrlId = json.getString("xbrlId"); // 票种
            String kpdate = json.getString("DateOfIssue"); // 开票时间
            String fpbillno = json.getString("UniqueCodeOfInvoice"); // 发票号
            String filepath = fileDirPathSrc.substring(0, fileDirPathSrc.lastIndexOf("\\"))+"\\"+xbrlId+"\\"+xbrlId+"_"+kpdate.replace("-", "")+"_"+fpbillno;
            String xml = filepath+ "\\"+xbrlId+".xml";
            File path = new File(filepath);
            ins = new ByteArrayInputStream(xmldate.getBytes());
            if(!path.exists()) {
                path.mkdirs();
                path.setReadable(true);
                path.setWritable(true);
                path.setExecutable(true);
            }
            baos = new FileOutputStream(xml);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = ins.read(buffer)) > 0) {
                baos.write(buffer, 0, length);
            }
            baos.flush();
        }catch(Exception e) {
            throw new Exception("浙里办票电子凭证下载失败:" + e.getMessage());
        }finally {
            if(ins != null) {ins.close();}
            if(baos != null) {baos.close();}
        }
    }
}
